package doc

import (
	"sort"

	"gitee.com/knowgo/ego/core"
	"gitee.com/knowgo/ego/core/function"
	"gitee.com/knowgo/ego/egoc"
)

type EgoApiDoc struct {
	C *core.Core
}

// func MakeCoreFactory(c *core.Core) func(ctx *context.Context) (*core.Core, error) {
// 	return func(ctx *context.Context) (*core.Core, error) {
// 		return c, nil
// 	}
// }

func (d *EgoApiDoc) Group() egoc.Group {
	return egoc.Group{
		Name:        "ego",
		Description: "api 文档接口",
	}
}

func (d *EgoApiDoc) GetApiInfo() egoc.FuncInfo {
	return egoc.FuncInfo{Description: "获取全部 api 分组及 api 列表"}
}

func (d *EgoApiDoc) GetApi(ctx *egoc.Context) (*Api, error) {
	var groups = d.C.GetGroups()
	var apis []*Group
	for _, g := range groups {
		var ag = &Group{
			Name:       g.Name,
			Desc:       g.Description,
			Deprecated: g.Deprecated,
		}

		for _, svc := range g.Services {
			var arg *ObjectInfo
			if svc.ArgumentType != nil {
				arg = argInfo2Obj(svc.ArgumentType.Info, false)
			}
			ag.Services = append(ag.Services, &Service{
				Name:           svc.Name,
				Desc:           svc.Desc,
				Deprecated:     svc.Deprecated,
				ArgIsRequire:   svc.ArgIsRequire,
				ResponseBinary: svc.IgnoreResponse,
				Upload:         svc.Upload,
				WebSocket:      svc.WebSocket,
				Arg:            arg,
				Info:           returnInfo2Obj(svc.ReturnType.Info, false),
			})
		}

		sort.Sort(Sorter[*Service](ag.Services))
		apis = append(apis, ag)
	}
	sort.Sort(Sorter[*Group](apis))

	var args = map[string]*ObjectInfo{}
	for id, arg := range d.C.ArgumentTypes {
		args[id] = argInfo2Obj(arg, true)
	}
	var infos = map[string]*ObjectInfo{}
	for id, res := range d.C.ReponseTypes {
		infos[id] = returnInfo2Obj(res, true)
	}

	return &Api{
		Apis:  apis,
		Args:  args,
		Infos: infos,
	}, nil
}

func argInfo2Obj(info *function.ArgumentTypeInfo, withFields bool) *ObjectInfo {
	obj := &ObjectInfo{
		Name:             info.Name,
		ReferenceID:      info.TypeId,
		Type:             info.Type,
		KeyType:          info.KeyType,
		JsonTypeIsString: info.JsonValueIsString,
		TimeFormat:       info.TimeFormat,
		Require:          info.Required,
		Range:            info.Range,
		Array:            info.Array,
		Description:      info.Description,
		// ReferenceID: svc.Info,
	}
	if len(info.Fields) > 0 {
		obj.ReferenceID = info.ID
		if withFields {
			for _, fd := range info.Fields {
				field := argInfo2Obj(fd, false)
				obj.Children = append(obj.Children, field)
			}
		}
	}
	return obj
}

func returnInfo2Obj(info *function.ResponseTypeInfo, withFields bool) *ObjectInfo {
	obj := &ObjectInfo{
		Name:        info.Name,
		ReferenceID: info.TypeId,
		Type:        info.Type,
		KeyType:     info.KeyType,
		// JsonTypeIsString: info.JsonValueIsString,
		// TimeFormat:       info.TimeFormat,
		// Require:          info.Required,
		// Range:            info.Range,
		Array:       info.Array,
		Description: info.Description,
		// ReferenceID: svc.Info,
	}
	if len(info.Fields) > 0 {
		obj.ReferenceID = info.ID
		if withFields {
			for _, fd := range info.Fields {
				field := returnInfo2Obj(fd, false)
				obj.Children = append(obj.Children, field)
			}
		}
	}
	return obj
}
